#!/bin/python3
# -*- coding:utf-8 -*-
"""
    奖池分配算法
    By :陈狍子 e4ting@qq.com 2024-12-22 16:55:31
"""
import sys,os
from pdb import set_trace as strace
from traceback  import format_exc as dumpstack

from collections import defaultdict

from e4ting import util,log

class PotTool():
    def __init__(self, awards):
        self.awards = awards
        self.total = sum(self.awards)

    def mean(self, num, tip):
        # 把不能平均分配的部分折算成小费
        if num <= 0:
            return self.total,0
        _tip = self.total % ( num * tip)
        return int((self.total - _tip) / num),_tip

    def __sub__(self, line):
        # 减去
        return PotTool([ max(0, a-line) for a in self.awards])

    def __lt__(self, line):
        # 把 小于 line 的部分取出来
        return PotTool([ line if line < a else a for a in self.awards])

    def __iter__(self):
        return iter(self.awards)

    def __repr__(self):
        return ",".join([str(i) for i in self.awards])

class Pot():
    def __init__(self, members, awards=None, taken_away=0, tip=10):
        self.tip = tip
        self.taken_away = taken_away # 已经被赢家拿走的部分
        self.pay_tip = 0
        self.init(members, awards)

    def init(self, members, awards):
        self.awards  = awards - self.taken_away
        self.members = [ Member(**info).init(self.taken_away, self.awards) for info in members]

    def partition(self):
        # 几个人开始平分这个池子
        if not any(self.awards):
            # 奖金已经全部被拿走了
            return self

        # 从小到大排序
        self.members.sort(key=lambda m: m.can_get)
        cash_list = [int(m) for m in self.members]
        # 每个成员都对应一个奖金梯度，每个梯度有多少人需要参与瓜分
        cash_map = defaultdict(list)
        cash_index = list(set(cash_list))
        cash_index.sort()
        for cash in cash_index:
            for m in self.members:
                if int(m) >= cash:
                    cash_map[cash].append(m)
        # log.info(cash_map)
        # 挨个梯度瓜分
        tips = [0]
        line = 0
        # log.info(f"--总 {self.awards.total}-------")
        for cash in cash_index:
            awards = (self.awards - line) < (cash - line)
            # log.info(f"{cash} 梯度 {len(cash_map[cash])} 个人瓜分 {awards}")
            money,tip = awards.mean( len(cash_map[cash]) , self.tip)
            # log.info(f"每人{money} * {len(cash_map[cash])} 小费 {tip} = {money * len(cash_map[cash]) + tip} ")
            tips.append(tip)
            for m in cash_map[cash]:
                m.put_award(money)
            line = cash
        # log.info("-------------------------")
        self.pay_tip = sum(tips)
        return self

    def __repr__(self):
        return f"[奖池{self.awards}]被拿走{self.taken_away} 成员:\n" + "\n".join([ str(m) for m in self.members ])

class Member():
    def __init__(self, uid=0, cash=0, score=0):
        self.uid   = uid
        self.cash  = cash
        self.score = score
        self.money = 0
        self.can_get=0

    def init(self, taken_away, awards):
        self.can_get = max(0, self.cash - taken_away)
        self.awards  = awards < self.can_get
        return self

    def __int__(self):
        return self.can_get

    def put_award(self, cash):
        # 发放奖金
        self.money += cash

    def __repr__(self):
        return f"\n[uid={self.uid}({self.score}, {self.cash})]可得{self.can_get} 奖池: {self.awards} , 最终收益 {self.money}"

class RewardPot():
    def __init__(self, data=[[]], tip=10):
        self.data = [ {"uid":uid, "cash":item[0], "score": item[1] } for uid,item in enumerate(data)]
        self.tip  = tip # 小费

    def is_end(self):
        # 是否分完了
        rewards = [ i[1] for i in self.data ]
        return sum(rewards) <= 0

    def init(self):
        self.awards = PotTool([i["cash"] for i in self.data]) # 先把奖金拿出来
        self.scores = list(set([i["score"] for i in self.data])) # 把得分去重
        self.scores.sort(reverse=True)
        # self.groups = defaultdict(list)
        # for item in self.data:
        #     self.groups[item[1]].append(item[0])
        # log.info(self.groups)
        return self

    def single_pot(self, s, mans):
        cash = max([i["cash"] for i in mans ])
        # 取走奖金
        # awards = [ cash if cash < a else a for a in self.awards]
        awards = self.awards < cash
        pot = Pot(mans, awards, taken_away=self.lastwin)
        # log.info(f"得分 {s} 者: {mans}, 奖金{pot.awards}")
        self.lastwin = max(cash, self.lastwin)
        # log.info(pot)
        return pot

    def calc_pots(self):
        # 按得分从大到小排序
        # self.data.sort( key=lambda x:x["score"], reverse=True)
        groups = defaultdict(list)
        for item in self.data:
            groups[item["score"]].append(item)

        self.lastwin = 0
        # log.info([i["score"] for i in self.data])
        # log.info(self.awards)
        self.pots = [ self.single_pot(s, groups[s]) for s in self.scores]

    def partition_pot(self):
        members = []
        tip = 0
        log.info("所有池总{t}".format(t=sum([ p.awards.total for p in self.pots])))
        for pot in self.pots:
            pot.partition()
            members += pot.members
            tip += pot.pay_tip
        # for m in members:
        #     log.info(m)
        log.info(f"支付小费{tip}")
        log.info("兑现奖励{t}".format(t=sum([m.money for m in members])))
        log.info("总计{t}".format(t=self.awards.total))
        self.results = {
            m.uid:m.money
            for m in members
        }
        self.results["tip"] = tip

    def run(self):
        # 分池
        self.calc_pots()
        # 瓜分
        self.partition_pot()
        return self

    def dump(self):
        return self.results


if __name__ == '__main__':
    RewardPot([
            [30,  4],
            [30,  4],
            [30,  4],
            [30,  4],
            [40,  3],
            [40,  3],
            [40,  3],
            [110,  2],
            [110,  2],
        ]).init().run()
